package com.library.management.entity;

import com.library.management.enums.FineReason;
import com.library.management.enums.FineStatus;
import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;

import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * 罚款记录实体类
 * 管理用户因各种原因产生的罚款记录
 *
 * 关联关系：
 * - 多对一：用户、借阅记录
 *
 * 业务功能：
 * - 罚款计算和记录
 * - 支付状态跟踪
 * - 罚款减免处理
 *
 * @author 开发者
 * @version 1.0
 * @since 2025-10-19
 */
@Entity
@Table(name = "fines", indexes = {
        @Index(name = "idx_fines_user_id", columnList = "user_id"),
        @Index(name = "idx_fines_borrow_record_id", columnList = "borrow_record_id"),
        @Index(name = "idx_fines_status", columnList = "status"),
        @Index(name = "idx_fines_created_time", columnList = "created_time")
})
@Data
@EqualsAndHashCode(exclude = {"user", "borrowRecord"})
@ToString(exclude = {"user", "borrowRecord"})
public class Fine {

    // ========== 主键标识 ==========

    /**
     * 罚款ID - 主键，自增长
     * 数据库字段：id (BIGINT, PRIMARY KEY, AUTO_INCREMENT)
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // ========== 关联关系 ==========

    /**
     * 用户 - 被罚款的用户
     * 多对一关系，外键关联users表
     * 延迟加载提高性能
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", nullable = false, foreignKey = @ForeignKey(name = "fk_fines_user_id"))
    private User user;

    /**
     * 借阅记录 - 产生罚款的借阅记录
     * 多对一关系，外键关联borrow_records表
     * 延迟加载提高性能
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "borrow_record_id", nullable = false, foreignKey = @ForeignKey(name = "fk_fines_borrow_record_id"))
    private BorrowRecord borrowRecord;

    // ========== 罚款信息 ==========

    /**
     * 罚款金额 - 总罚款金额
     * 数据库字段：fine_amount (DECIMAL(10,2)), NOT NULL
     */
    @Column(name = "fine_amount", nullable = false, precision = 10, scale = 2)
    private BigDecimal fineAmount;

    /**
     * 罚款原因 - 产生罚款的原因
     * OVERDUE: 逾期，LOST: 遗失，DAMAGED: 损坏
     * 数据库字段：fine_reason (ENUM), NOT NULL
     */
    @Enumerated(EnumType.STRING)
    @Column(name = "fine_reason", nullable = false, length = 20)
    private FineReason fineReason;

    /**
     * 详细说明 - 罚款的详细描述
     * 数据库字段：description (TEXT)
     */
    @Column(columnDefinition = "TEXT")
    private String description;

    // ========== 支付信息 ==========

    /**
     * 已支付金额 - 用户已支付的金额
     * 数据库字段：paid_amount (DECIMAL(10,2)), DEFAULT 0.00
     */
    @Column(name = "paid_amount", precision = 10, scale = 2)
    private BigDecimal paidAmount = BigDecimal.ZERO;

    /**
     * 支付日期 - 最近一次支付时间
     * 数据库字段：payment_date (DATETIME)
     */
    @Column(name = "payment_date")
    private LocalDateTime paymentDate;

    /**
     * 支付方式 - 支付方式描述
     * 数据库字段：payment_method (VARCHAR(50))
     */
    @Column(name = "payment_method", length = 50)
    private String paymentMethod;

    /**
     * 支付状态 - 当前支付状态
     * UNPAID: 未支付，PARTIAL: 部分支付，PAID: 已支付，WAIVED: 已减免
     * 数据库字段：status (ENUM), NOT NULL
     */
    @Enumerated(EnumType.STRING)
    @Column(nullable = false, length = 20)
    private FineStatus status = FineStatus.UNPAID;

    // ========== 审计字段 ==========

    /**
     * 创建人ID - 记录创建者
     * 数据库字段：created_by (BIGINT)
     */
    @Column(name = "created_by")
    private Long createdBy;

    /**
     * 创建时间 - 记录创建时间，自动生成
     * 数据库字段：created_time (DATETIME), DEFAULT CURRENT_TIMESTAMP
     */
    @CreationTimestamp
    @Column(name = "created_time", updatable = false)
    private LocalDateTime createdTime;

    /**
     * 更新时间 - 记录最后修改时间，自动更新
     * 数据库字段：updated_time (DATETIME), DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
     */
    @UpdateTimestamp
    @Column(name = "updated_time")
    private LocalDateTime updatedTime;

    // ========== 业务方法 ==========

    /**
     * 检查罚款是否已完全支付
     * 已支付金额 >= 罚款金额
     *
     * @return true-已完全支付，false-未完全支付
     */
    public boolean isFullyPaid() {
        return this.paidAmount.compareTo(this.fineAmount) >= 0;
    }

    /**
     * 检查罚款是否部分支付
     * 已支付金额 > 0 且 < 罚款金额
     *
     * @return true-部分支付，false-未支付或已完全支付
     */
    public boolean isPartiallyPaid() {
        return this.paidAmount.compareTo(BigDecimal.ZERO) > 0 &&
                this.paidAmount.compareTo(this.fineAmount) < 0;
    }

    /**
     * 获取待支付金额
     * 罚款金额 - 已支付金额
     *
     * @return 待支付金额
     */
    public BigDecimal getRemainingAmount() {
        return this.fineAmount.subtract(this.paidAmount).max(BigDecimal.ZERO);
    }

    /**
     * 支付罚款
     * 更新支付信息，自动计算支付状态
     *
     * @param amount 支付金额
     * @param method 支付方式
     * @return true-支付成功，false-支付失败
     */
    public boolean payFine(BigDecimal amount, String method) {
        if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            return false; // 支付金额必须大于0
        }

        if (this.status == FineStatus.PAID || this.status == FineStatus.WAIVED) {
            return false; // 已支付或已减免的罚款不能再次支付
        }

        this.paidAmount = this.paidAmount.add(amount);
        this.paymentMethod = method;
        this.paymentDate = LocalDateTime.now();

        // 更新支付状态
        if (isFullyPaid()) {
            this.status = FineStatus.PAID;
        } else if (isPartiallyPaid()) {
            this.status = FineStatus.PARTIAL;
        }

        return true;
    }

    /**
     * 减免罚款（管理员操作）
     * 将罚款状态设置为已减免，清空待支付金额
     */
    public void waiveFine() {
        this.status = FineStatus.WAIVED;
        this.paidAmount = this.fineAmount; // 标记为已全额支付（减免）
        this.paymentDate = LocalDateTime.now();
        this.paymentMethod = "减免";
        this.description = (this.description == null ? "" : this.description) +
                " [罚款已减免，减免金额：" + this.fineAmount + "元]";
    }

    /**
     * 检查罚款是否已过期
     * 超过一定时间未支付的罚款视为过期（示例：90天）
     *
     * @param expiryDays 过期天数
     * @return true-已过期，false-未过期
     */
    public boolean isExpired(int expiryDays) {
        if (this.status == FineStatus.PAID || this.status == FineStatus.WAIVED) {
            return false; // 已支付或已减免的罚款不会过期
        }

        LocalDateTime expiryDate = this.createdTime.plusDays(expiryDays);
        return LocalDateTime.now().isAfter(expiryDate);
    }

    /**
     * 获取罚款产生天数
     * 从创建时间到当前时间的天数
     *
     * @return 罚款产生天数
     */
    public long getFineAge() {
        return java.time.Duration.between(this.createdTime, LocalDateTime.now()).toDays();
    }
}